﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Delsjö.Resources;
using System.IO;
using System.Xml.Linq;
using System.Linq;
using Windows.Devices.Geolocation;
using System.IO.IsolatedStorage;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Delsjö.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public MainViewModel()
        {
            this.Items = new ObservableCollection<ItemViewModel>();

        }

        /// <summary>
        /// A collection for ItemViewModel objects.
        /// </summary>
        public ObservableCollection<ItemViewModel> Items { get; private set; }

        private string _header = delsjomotetName;
        /// <summary>
        /// Sample ViewModel property; this property is used in the view to display its value using a Binding
        /// </summary>
        /// <returns></returns>
        public string Header
        {
            get
            {
                return _header;
            }
            set
            {
                if (value != _header)
                {
                    _header = value;
                    NotifyPropertyChanged("Header");
                }
            }
        }

        public bool IsDataLoaded
        {
            get;
            set;
        }

        RouteViewModel routeVM = new RouteViewModel();

        const string delsjomotetName = "Delsjömotet";

        class Location
        {
            public string Id;
            public double Latitude;
            public double Longitude;
            public double DistanceFromCurrentLocation;
        }

        Location packhusplatsen = new Location() { Id = "9022014005240002", Latitude = 57.706791, Longitude = 11.959734 };
        Location delsjomotet = new Location() { Id = "9022014002043002", Latitude = 57.676399, Longitude = 12.025562 };
        Location heden = new Location() { Id = "9022014003127002", Latitude = 57.702171, Longitude = 11.974269 };
        Location korsvagen = new Location() { Id = "9022014003980004", Latitude = 57.696858, Longitude = 11.986989 };
        Location nordstanC = new Location() { Id = "9022014004945003", Latitude = 57.709407, Longitude = 11.970449 };
        Location centralstationenJ = new Location() { Id = "9022014001950010", Latitude = 57.708598, Longitude = 11.975204 };

        Geocoordinate coordinate = null;

        public async Task<Windows.Devices.Geolocation.Geocoordinate> GetSinglePositionAsync()
        {
            Windows.Devices.Geolocation.Geolocator geolocator = new Windows.Devices.Geolocation.Geolocator();
            geolocator.DesiredAccuracyInMeters = 50;

            Windows.Devices.Geolocation.Geoposition geoposition = await geolocator.GetGeopositionAsync(
                maximumAge: TimeSpan.FromMinutes(1),
                timeout: TimeSpan.FromSeconds(30)
                );

            return geoposition.Coordinate;
        }
/*
        public async void GetLocation()
        {
            if ((bool)IsolatedStorageSettings.ApplicationSettings["LocationConsent"] != true)
            {
                // The user has opted out of Location.
                coordinate = null;
                return;
            }

            Geolocator geolocator = new Geolocator();
            geolocator.DesiredAccuracyInMeters = 50;

            try
            {
                Geoposition geoposition = await Task.Run(() => geolocator.GetGeopositionAsync(
                    maximumAge: TimeSpan.FromMinutes(5),
                    timeout: TimeSpan.FromSeconds(10)
                    ));

                coordinate = geoposition.Coordinate;
            }
            catch (Exception ex)
            {
                if ((uint)ex.HResult == 0x80004004)
                {
                    // the application does not have the right capability or the location master switch is off
                    //StatusTextBlock.Text = "location is disabled in phone settings.";
                }
                //else
                {
                    // something else happened acquiring the location
                }
                coordinate = null;
            }
        }
*/
        public async void GetTrips()
        {
            Items.Clear();

            try
            {
                coordinate = await Task.Run(() => GetSinglePositionAsync());
            }
            catch (Exception ex)
            {
                // No location service... ignore it.
            }

            List<Location> fromLocations = new List<Location>();
            fromLocations.Add(packhusplatsen);
            fromLocations.Add(nordstanC);
            fromLocations.Add(centralstationenJ);
            fromLocations.Add(heden);
            fromLocations.Add(korsvagen);

            Location shortestDistanceLocation = null;
            double shortestDistance = 0;
            int numShortest = -1;
            if (coordinate != null)
            {
                foreach(var location in fromLocations)
                {
                    location.DistanceFromCurrentLocation = GeoDistance.distance(coordinate.Latitude, coordinate.Longitude, location.Latitude, location.Longitude);
                    if (shortestDistanceLocation == null || location.DistanceFromCurrentLocation < shortestDistance)
                    {
                        shortestDistanceLocation = location;
                        shortestDistance = location.DistanceFromCurrentLocation;
                        numShortest++;
                    }
                }
            }
            if (numShortest > 0)
            {
                fromLocations.RemoveRange(0, numShortest);
            }

            var orderedLocations = fromLocations.OrderBy(l => l.DistanceFromCurrentLocation);
            foreach (var location in orderedLocations)
            {
                var result = await HttpUtil.GetStringResponseFromURL(
                    "http://api.vasttrafik.se/bin/rest.exe/v1/trip?authKey=78e561b6-4a44-4dcb-8cba-6f2706404c7f&originId=" + location.Id + "&destId=" + delsjomotet.Id);
                GetTripDetails(result);
            }

            // Remove all WALK suggestions
            routeVM.Trips.RemoveAll(t => t.Legs[0].Type == "WALK");

            // Max three steps in the trip
            routeVM.Trips.RemoveAll(t => t.Legs.Count >= 3);

            // Max 20 minutes until ride
            var orderedTripsByTime = routeVM.Trips.OrderBy(t => t.Legs[0].OriginTime);
            DateTime lowestTime = orderedTripsByTime.First().Legs[0].OriginTime;
            TimeSpan longestTimeSpan = new TimeSpan(0, 20, 0);
            routeVM.Trips.RemoveAll(t => (t.Legs[0].OriginTime - lowestTime) > longestTimeSpan);

            var orderedTrips = routeVM.Trips;//.OrderBy(t => t.Legs[0].OriginTime);
            foreach (var trip in orderedTrips)
            {
                Items.Add(new ViewModels.ItemViewModel() { LineTwo = trip.Origins + " : " + trip.Name, LineOne = trip.Time, LineThree = trip.Origins });
            }

            
            IsDataLoaded = true;
        }

        public void GetTripDetails(string result)
        {
            try
            {
                using (var stream = new StringReader(result))
                {
                    XDocument doc = XDocument.Load(stream);
                    var xTrips = from c in doc.Descendants("Trip") select c;

                    foreach (var xTrip in xTrips)
                    {
                        Trip trip = new Trip();

                        var xLegs = from c in xTrip.Descendants("Leg") select c;
                        foreach (var xLeg in xLegs)
                        {
                            Leg leg = new Leg();
                            leg.Name = xLeg.Attribute(XName.Get("name")).Value;
                            leg.Type = xLeg.Attribute(XName.Get("type")).Value;

                            var xOrigin = xLeg.Element(XName.Get("Origin"));
                            leg.Origin = xOrigin.Attribute(XName.Get("name")).Value;

                            if (xOrigin.Attribute(XName.Get("time")) != null)
                            {
                                leg.OriginTimeString = xOrigin.Attribute(XName.Get("time")).Value;
                                if (!string.IsNullOrEmpty(leg.OriginTimeString))
                                    leg.OriginTime = Convert.ToDateTime(leg.OriginTimeString);
                            }
                            if (xOrigin.Attribute(XName.Get("rtTime")) != null)
                            {
                                leg.OriginTimeStringRT = xOrigin.Attribute(XName.Get("rtTime")).Value;
                                if (!string.IsNullOrEmpty(leg.OriginTimeStringRT))
                                    leg.OriginTimeRT = Convert.ToDateTime(leg.OriginTimeStringRT);
                            }

                            var xDestination = xLeg.Element(XName.Get("Destination"));
                            leg.Destination = xDestination.Attribute(XName.Get("name")).Value;

                            if (xDestination.Attribute(XName.Get("time")) != null)
                            {
                                leg.DestinationTimeString = xDestination.Attribute(XName.Get("time")).Value;
                                if (!string.IsNullOrEmpty(leg.DestinationTimeString))
                                    leg.DestinationTime = Convert.ToDateTime(leg.DestinationTimeString);
                            }
                            if (xDestination.Attribute(XName.Get("rtTime")) != null)
                            {
                                leg.DestinationTimeStringRT = xDestination.Attribute(XName.Get("rtTime")).Value;
                                if (!string.IsNullOrEmpty(leg.DestinationTimeStringRT))
                                    leg.DestinationTimeRT = Convert.ToDateTime(leg.DestinationTimeStringRT);
                            }

                            leg.Origin = leg.Origin.Replace(", Göteborg", "");
                            leg.Destination = leg.Destination.Replace(", Göteborg", "");
                            trip.Legs.Add(leg);
                        }

                        if (trip.Legs.Count > 0)
                        {
                            routeVM.Trips.Add(trip);
                        }
                    }
                }
            }
            catch(Exception e)
            {
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}